package cl.uchile.sketchpad.web.controllers;

import static org.springframework.web.bind.annotation.RequestMethod.POST;
import static org.springframework.web.bind.annotation.RequestMethod.GET;

import java.io.ByteArrayInputStream;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.Comparator;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import cl.uchile.sketchpad.persistance.model.UploadedFile;
import cl.uchile.sketchpad.persistance.model.User;
import cl.uchile.sketchpad.services.ActivityService;
import cl.uchile.sketchpad.services.SlideService;
import cl.uchile.sketchpad.services.UploadedFileService;
import cl.uchile.sketchpad.services.UserService;

@Controller
public class FilesController {
	
	private static final Logger LOG = LoggerFactory.getLogger(FilesController.class);
	
	@Autowired private UserService userService;
	@Autowired private UploadedFileService uploadedFileService;
	@Autowired private SlideService slideService;
	@Autowired private ActivityService activityService;
	
	@Transactional
	@RequestMapping(value = "/upload", produces = "application/json", method = POST)
	public @ResponseBody UploadedFile upload(
			HttpServletRequest request,
			@RequestParam("file") MultipartFile file
	) {
		User user = this.userService.getUser(request);
		if ( user == null || user.getId() == null )
			return null;
		try {
			return this.uploadedFileService.saveFile(file);
		} catch ( Exception e ) {
			e.printStackTrace(System.err);
			LOG.error(e.getLocalizedMessage(), e);
		}
		return null;
	}

	@Transactional
	@RequestMapping(value = "/uploadMany", produces = "application/json", method = POST)
	public @ResponseBody List<UploadedFile> uploadMany(
			HttpServletRequest request,
			@RequestParam("files[]") MultipartFile[] files
	) {

		User user = this.userService.getUser(request);
		if ( user == null || user.getId() == null )
			return null;
		
		List<MultipartFile> sortedFiles = Arrays.asList(files);
		Collections.sort(sortedFiles, new Comparator<MultipartFile>() {
			@Override
			public int compare(MultipartFile o1, MultipartFile o2) {
				Pattern p = Pattern.compile("\\d+");
				Matcher m1 = p.matcher(o1.getOriginalFilename());
				Matcher m2 = p.matcher(o2.getOriginalFilename());
				Integer n1 = null;
				Integer n2 = null;
				
				while ( m1.find() ) {
					try {
						n1 = new Integer(m1.group());
					} catch (Exception e) { }
				}
				while ( m2.find() ) {
					try {
						n2 = new Integer(m2.group());	
					} catch ( Exception e ) { }
				}
				
				if ( n1 != null && n2 != null )
					return n1.compareTo(n2);
				else
					return o1.getOriginalFilename().compareTo(o2.getOriginalFilename());
			}
		});
		
		try {
			return this.uploadedFileService.saveFiles(sortedFiles);
		} catch ( Exception e ) {
			e.printStackTrace(System.err);
			LOG.error(e.getLocalizedMessage(), e);
		}
		
		return null;
	}
	
	@Transactional
	@RequestMapping(value = "/files/{id}/*", method = GET)
	public void download(
			HttpServletRequest request, 
			HttpServletResponse response, 
			@PathVariable Long id
	) {
		try {
			UploadedFile uploadedFile = this.uploadedFileService.findById(id);
			if ( uploadedFile == null ) {
				String error = "File not found: " + request.getRequestURI(); 
				System.err.println(error);
				LOG.error(error);
				response.sendError(404);
			} else {
				response.setContentType(uploadedFile.getContentType());
				IOUtils.copy( 
					new ByteArrayInputStream( Base64.decodeBase64( uploadedFile.getContent() ) ),
					response.getOutputStream() 
				);
				response.flushBuffer();
			}
		} catch (Exception e) {
			e.printStackTrace(System.err);
			LOG.error(e.toString(), e);
		}
	}
	
}
